package com.atguigu.tingshu.album.init;

import jakarta.annotation.PostConstruct;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @Author GQS @Date 2024/11/5/16:55 @Description
 * rabbitMQ的可靠性投递的配置
 */
@Component
@Log4j2
public class RabbitConfirmAndReturnInit implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {

  @Autowired
  private RabbitTemplate rabbitTemplate;

  @Autowired
  private RedisTemplate redisTemplate;
  /**
   * 配置可靠性投递
   */
  @PostConstruct
  public void init(){
    rabbitTemplate.setMandatory(true);
    rabbitTemplate.setConfirmCallback(this::confirm);
    rabbitTemplate.setReturnsCallback(this::returnedMessage);
  }

  /**
   * confirm模式的回调函数: 是否抵达交换机都会触发
   * @param correlationData: 消息元数据,记录消息的编号,确认消息是否被反复发送(重复发送可以用这个来进行校验)
   * @param b: 是否抵达了交换机
   * @param s: 没有抵达的错误是什么,抵达了就是null
   */
  @Override
  public void confirm(CorrelationData correlationData, boolean b, String s) {
    // 获取消息
    ReturnedMessage returned = correlationData.getReturned(); // 空指针 已解决
    // 获取消息内容
    String albumId = new String(returned.getMessage().getBody());
    // 消息没抵达交换机
    if (!b){
      // 兜底方法处理
      markFailInfo(albumId);
    }
  }

  /***
   * returnedMessage模式的回调函数: 不抵达队列才触发
   * @param returnedMessage
   */
  @Override
  public void returnedMessage(ReturnedMessage returnedMessage) {
    // 获取消息
    Message message = returnedMessage.getMessage();
    String albumId = new String(message.getBody());
    // 兜底方法处理
    markFailInfo(albumId);
  }

  /**
   * 消息发送失败兜底处理: 专辑最终应该是个什么状态,是否和当前routingkey一致
   * @param albumId
   */
  private void markFailInfo(String albumId) {
    // 将发送失败的消息放入Redis
    redisTemplate.opsForSet().add("album_upper_or_down", albumId);
  }



}
